<?php

namespace Houdunren\WeChat;


use hisorange\BrowserDetect\Exceptions\Exception;
use Houdunren\WeChat\Message\Send;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WeChat
{
    use Send;

    //存入公共的api位置暂存
    protected $api = 'https://api.weixin.qq.com/cgi-bin';
    public static $config;

    public function init($config)
    {

        $this->config($config);
        $this->bind(); //服务器与微信服务器绑定
//        file_put_contents('a.php', '<?php return' . var_export((array)$this->message, true));
        return $this;
    }

    protected function config($data)
    {

        if (is_string($data)) {

            return self::$config[$data] ?? null;
        } else {
            self::$config = $data;
        }
    }

    public function message()
    {
        //php://input 获取服务器得输入流
        $content = file_get_contents('php://input');

        if ($content) {
            return simplexml_load_string($content);
        }


    }

    public function bind()
    {

        //接入时会有，$_GET['signature']，$_GET["timestamp"]，$_GET["nonce"]的参数，其他情况是没有的
        if (isset($_GET["signature"]) && isset($_GET["timestamp"]) && isset($_GET["nonce"]) && isset($_GET["echostr"])) {
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];

            $token = $this->config('token');

            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr, SORT_STRING);
            $tmpStr = implode($tmpArr);
            $tmpStr = sha1($tmpStr);

            if ($tmpStr == $signature) {
                //关注时应返回$_GET['echostr'];
                die($_GET['echostr']);
            } else {
                return false;
            }
        }

    }

    public function token()
    {

        $url = $this->api . '/token?grant_type=client_credential&appid=' . $this->config('appID') . '&secret=' . $this->config('appsecret');
        //laravel http客户端不会引发异常，可以使用throw
        //缓存token
        //md5可以进行对比 bcrypt() 每次都不一样
        $cacheName = md5($url);
        if (!Cache::has($cacheName)) {
            $response = Http::get($url)->throw()->json();

            Cache::put($cacheName, $response['access_token'], now()->addSecond($response['expires_in']));
        }
        return Cache::get($cacheName);
    }

    public function __get($name)
    {
        //解决单例模式
        //在多个子类公用一个父类属性时，子类实例化后，会重新实例一个不同的父类，所以没有办法公用属性。
        //解决单例问题可以使用get_called_class方式。
        //但我们这里通过message名称判断动态获取input数据流，这样每个实例在获取message时就会获得最新的数据流

        if ($name == 'message') {

            return $this->message();
        }

        return $this->message()->$name ?? null;

    }

//自定义微信错误提示
    public function return($response)
    {

        if (isset($response['errcode']) && $response['errcode'] > 0) {
            $zh = include __DIR__ . '/zh.php';

            throw new Exception($zh[$response['errcode']] ?? $response['errmsg']);
        }
        return $response;
    }
}
